#include <iostream>
#include <stdio.h>
#include <unistd.h>
#include <string>
#include <vector>
#include <functional>
#include <sys/wait.h>
#include "Channel.hpp"
#include"Task.hpp"

using work_t = std::function<void()>;

enum
{
    OK = 0,
    UsageError,
    PipeError,
    ForkError
};

class ProcessPool
{
public:

ProcessPool(int _number,work_t _t):number(_number),work(_t)
{
    InintPool();
}
    int InintPool()
    {
        for (int i = 0; i < number; i++)
        {
            // 先创建管道，在创建子进程
            int fd[2] = {0};
            if (pipe(fd) == -1)
            {
                return PipeError;
            }

            int pid = fork();
            if (pid == -1)
            {
                return ForkError;
            }
            else if (pid == 0)
            {
                //这里我们为了避免子进程多写端问题，进行前面的写端关闭
                //这个时候父进程还没有将新创建的写端压入
                for(auto a:Channels)
                {
                    a.close_pipe();
                }
                ::close(fd[1]);
                // 输入重定向
                dup2(fd[0], 0);
                work();
                std::exit(OK);
            }
            ::close(fd[0]);
            // Channel ch(fd[0],getpid());
            // Channels.push_back(ch);
            Channels.emplace_back(fd[1], pid);
        }
        return OK;
    }

    void Task_sent()
    {
        // 任务派发
        int channel_number = 0;
        int sent_taskNumber = 15;

        while (sent_taskNumber)
        {
            // 选择任务
            task.Task_select();
            // 选择进程
            Channel ch = Channels[channel_number++];
            sent_taskNumber--;
            std::cout << "###################################" << std::endl;

            std::cout << ch.get_name() << '-' << ch.get_pid() << "剩下的任务量：" << sent_taskNumber << std::endl;

            std::cout << "###################################" << std::endl;

            channel_number %= Channels.size();
            // 派发任务
            ch.sent_task(task.Task_select());
            sleep(1);
        }
    }

    void celan_processPool()
    {
        // 进程回收
        //对于进程回收的实现容易会因为子进程的继承，导致子进程有多个写入端

        for (auto &a : Channels)
        {
            a.close_pipe();
        }

        for (auto &a : Channels)
        {
            pid_t rid = ::waitpid(a.get_pid(), nullptr, 0);
            if (rid > 0)
            {
                std::cout << a.get_name() << rid << "wait success......" << std::endl;
            }
        }
    }

private:
    std::vector<Channel> Channels;
    int number;
    work_t work;
};
